From d96882bc163ee18969c760f1065ec26a3b5a34c2 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Sat, 24 Aug 2013 21:35:48 -0700 Subject: [PATCH] textview: use pixelcache to indirectly renderer to widget. This patch uses GtkPixelCache to render the contents of the widget, and typically a bit more, to an offscreen surface. The pixel cache in turn manages rendering to the actual surface for the widget. The current strategy for the size to render is the size of the widget plus half the height. https://bugzilla.gnome.org/show_bug.cgi?id=701125 --- gtk/gtktextview.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 889aab297f..8a96a56427 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -53,6 +53,7 @@ #include "gtkcssstylepropertyprivate.h" #include "gtkbubblewindowprivate.h" #include "gtktoolbar.h" +#include "gtkpixelcacheprivate.h" #include "a11y/gtktextviewaccessibleprivate.h" @@ -200,6 +201,8 @@ struct _GtkTextViewPrivate GtkTextPendingScroll *pending_scroll; + GtkPixelCache *pixel_cache; + /* Default style settings */ gint pixels_above_lines; gint pixels_below_lines; @@ -238,6 +241,8 @@ struct _GtkTextViewPrivate guint cursor_handle_dragged : 1; guint selection_handle_dragged : 1; guint populate_all : 1; + + gboolean in_scroll : 1; }; struct _GtkTextPendingScroll @@ -524,6 +529,9 @@ static void gtk_text_view_update_handles (GtkTextView *text_view static void gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view); static void gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view); +static void gtk_text_view_queue_draw_region (GtkWidget *widget, + const cairo_region_t *region); + /* FIXME probably need the focus methods. */ @@ -661,7 +669,9 @@ gtk_text_view_class_init (GtkTextViewClass *klass) widget_class->drag_data_received = gtk_text_view_drag_data_received; widget_class->popup_menu = gtk_text_view_popup_menu; - + + widget_class->queue_draw_region = gtk_text_view_queue_draw_region; + container_class->add = gtk_text_view_add; container_class->remove = gtk_text_view_remove; container_class->forall = gtk_text_view_forall; @@ -1459,6 +1469,9 @@ gtk_text_view_init (GtkTextView *text_view) gtk_widget_set_can_focus (widget, TRUE); + priv->pixel_cache = _gtk_pixel_cache_new (); + _gtk_pixel_cache_set_content (priv->pixel_cache, CAIRO_CONTENT_COLOR_ALPHA); + /* Set up default style */ priv->wrap_mode = GTK_WRAP_NONE; priv->pixels_above_lines = 0; @@ -3133,6 +3146,12 @@ gtk_text_view_destroy (GtkWidget *widget) priv->im_spot_idle = 0; } + if (priv->pixel_cache) + { + _gtk_pixel_cache_free (priv->pixel_cache); + priv->pixel_cache = NULL; + } + GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget); } @@ -3682,6 +3701,9 @@ gtk_text_view_size_allocate (GtkWidget *widget, DV(g_print(G_STRLOC"\n")); + _gtk_pixel_cache_set_extra_size (priv->pixel_cache, 0, + allocation->height / 2); + gtk_widget_get_allocation (widget, &widget_allocation); size_changed = widget_allocation.width != allocation->width || @@ -5214,10 +5236,20 @@ gtk_text_view_paint (GtkWidget *widget, cairo_restore (cr); } +static void +draw_text (cairo_t *cr, + gpointer user_data) +{ + GtkWidget *widget = user_data; + + gtk_text_view_paint (widget, cr); +} + static gboolean gtk_text_view_draw (GtkWidget *widget, cairo_t *cr) { + GtkTextViewPrivate *priv = ((GtkTextView *)widget)->priv; GSList *tmp_list; GdkWindow *window; GtkStyleContext *context; @@ -5241,10 +5273,29 @@ gtk_text_view_draw (GtkWidget *widget, GTK_TEXT_WINDOW_TEXT); if (gtk_cairo_should_draw_window (cr, window)) { + cairo_rectangle_int_t view_rect; + cairo_rectangle_int_t canvas_rect; + GtkAllocation alloc; + DV(g_print (">Exposed ("G_STRLOC")\n")); + + gtk_widget_get_allocation (widget, &alloc); + + view_rect.x = 0; + view_rect.y = 0; + view_rect.width = gdk_window_get_width (window); + view_rect.height = gdk_window_get_height (window); + + canvas_rect.x = -gtk_adjustment_get_value (priv->hadjustment); + canvas_rect.y = -gtk_adjustment_get_value (priv->vadjustment); + canvas_rect.width = priv->cached_size_request.width; + canvas_rect.height = priv->cached_size_request.height; + cairo_save (cr); gtk_cairo_transform_to_window (cr, widget, window); - gtk_text_view_paint (widget, cr); + _gtk_pixel_cache_draw (priv->pixel_cache, cr, window, + &view_rect, &canvas_rect, + draw_text, widget); cairo_restore (cr); } @@ -8911,6 +8962,45 @@ text_window_free (GtkTextWindow *win) g_free (win); } +static void +gtk_text_view_queue_draw_region (GtkWidget *widget, + const cairo_region_t *region) +{ + GtkTextView *text_view = GTK_TEXT_VIEW (widget); + + /* There is no way we can know if a region targets the + not-currently-visible but in pixel cache region, so we + always just invalidate the whole thing whenever the + text view gets a queue draw. This doesn't normally happen + in normal scrolling cases anyway. */ + _gtk_pixel_cache_invalidate (text_view->priv->pixel_cache, NULL); + + GTK_WIDGET_CLASS (gtk_text_view_parent_class)->queue_draw_region (widget, + region); +} + +static void +text_window_invalidate_handler (GdkWindow *window, + cairo_region_t *region) +{ + gpointer widget; + GtkTextView *text_view; + int y; + + gdk_window_get_user_data (window, &widget); + text_view = GTK_TEXT_VIEW (widget); + + /* Scrolling will invalidate everything in the bin window, + * but we already have it in the cache, so we can ignore that */ + if (text_view->priv->in_scroll) + return; + + y = gtk_adjustment_get_value (text_view->priv->vadjustment); + cairo_region_translate (region, 0, y); + _gtk_pixel_cache_invalidate (text_view->priv->pixel_cache, region); + cairo_region_translate (region, 0, -y); +} + static void text_window_realize (GtkTextWindow *win, GtkWidget *widget) @@ -8939,6 +9029,9 @@ text_window_realize (GtkTextWindow *win, win->window = gdk_window_new (window, &attributes, attributes_mask); + gdk_window_set_invalidate_handler (win->window, + text_window_invalidate_handler); + gdk_window_show (win->window); gtk_widget_register_window (win->widget, win->window); gdk_window_lower (win->window); @@ -9050,7 +9143,9 @@ text_window_scroll (GtkTextWindow *win, { if (priv->selection_bubble) _gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble)); + view->priv->in_scroll = TRUE; gdk_window_scroll (win->bin_window, dx, dy); + view->priv->in_scroll = FALSE; } } -- 2.30.2